package com.appleyk.sso.config;

import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * <p>越努力，越幸运</p>
 * security配置
 * @author appleyk
 * @version V.0.1.1
 * @blob https://blog.csdn.net/appleyk
 * @date created on  5:17 下午 2021/1/10
 */
@EnableWebSecurity
// 开启方法授权方式
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    // 配置认证管理器
    @Bean
    public AuthenticationManager authenticationManager() throws Exception{
        return super.authenticationManager();
    }

    /**采用bcrypt加密算法，特点就是加密慢，每次加密得到的hash串都不一样，很安全，想要破解，会让你等到奔溃*/
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    // 安全拦截机制（很重要）
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * CSRF是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法
         * 跟跨网站脚本（XSS）相比，XSS 利用的是用户对指定网站的信任，
         * CSRF 利用的是网站对用户网页浏览器的信任。
         * 关闭，否则用户身份验证时要传csrf token
         */
        http.csrf().disable();
        http.authorizeRequests()
                /**一定注意放行的顺序！！！！！*/
                /**web授权，建议使用权限而不是角色，通过过滤器拦截用户请求，判断用户是否有访问下面这些资源的权限，如果有放行*/
                // 访问资源r1需要权限p1
                .antMatchers("/auth/r/r1").hasAuthority("p1")
                // 访问资源r2需要权限p2
                .antMatchers("/auth/r/r2").hasAuthority("p2")
                // 除了上面两个资源需要授权认证以外，/auth/r/**其他api均需要身份认证（登录）
                .antMatchers("/auth/r/**").authenticated()
                // 除此之外，其余api访问均放行（即不需要身份认证和授权）
                .anyRequest().permitAll()
                // 一个配置结束
                .and()
                // 采用表单的方式（一共有两种，一种是表单，一种是http的弹窗）
                .formLogin()
                // 自定义登录页，这个url会被thymeleaf捕获到，并返回指定的html页面
                .loginPage("/login")
                // 指定登录成功跳转的api
                .successForwardUrl("/auth/login-success")
                // 指定登录失败跳转的api
                .failureForwardUrl("/auth/login-failure")
                .and()
                // 自定义退出登录
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/auth/logout")
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
    }
}
